package com.custom.gobang

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.os.Bundle
import android.os.Parcelable
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.Toast
import java.lang.Math.min

/**
 * @description：游戏棋盘逻辑View
 * @Author MRyan
 * @Date 2020/4/7 9:42
 * @Version 1.0
 */
class GobanView : View {
    private val TAG: String = "GobanView"

    //测量布局宽度
    private var mWidthSize: Int? = 0

    //测量布局高度
    private var heightSize: Int? = 0

    //棋盘宽度 正方形
    private var mGobanWidth: Int? = 0

    //棋盘颜色
    private var mGobanBgcolor: Int? = 0

    //获胜条件
    private var mGobanNumber: Int? = 0

    //白棋子位置集合
    private lateinit var mWhitepoints: ArrayList<Point>

    //黑棋子位置集合
    private lateinit var mBlackpoints: ArrayList<Point>

    //一个格的高度
    private var mLineHeight: Float? = 0f

    //棋盘宽度
    private var mPanelWidth: Int? = 0

    //最大格数
    private var mMaxLine: Int = 15

    //绘制棋盘画笔
    private lateinit var mPaint: Paint

    //绘制白色棋子
    private lateinit var mWhiteBitmap: Bitmap

    //绘制黑色棋子
    private lateinit var mBlackBitmap: Bitmap

    //根据棋子和格的比例算出的棋子大小 是mLineHeight的3/4
    private var mRatioHeight: Int? = 0

    //判断是否当前为白棋在下
    private var mIsWhite: Boolean = true

    private var mIsWhiteWin: Boolean = false
    private var mIsBlackWin: Boolean = false

    //是否结束游戏
    private var isfinsh: Boolean = false


    constructor(context: Context) : super(context) {}
    constructor(
        context: Context,
        attrs: AttributeSet
    ) : super(context, attrs) {
        //初始化
        init();
        //获取自定义属性
        initAttr(context, attrs)
        setBackgroundColor(mGobanBgcolor!!)

    }

    /**
     * 初始化
     */
    private fun init() {
        mWhitepoints = ArrayList()
        mBlackpoints = ArrayList()
        //初始化画笔
        mPaint = Paint().apply {
            color = Color.parseColor("#88000000")
            isAntiAlias = true
            isDither = true
            style = Paint.Style.STROKE
            strokeWidth = 4F
        }
        mWhiteBitmap = BitmapFactory.decodeResource(resources, R.drawable.qiwhite)
        mBlackBitmap = BitmapFactory.decodeResource(resources, R.drawable.qiblack)

    }

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, 0) {
    }

    /**
     * 测量布局
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        mWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSize = MeasureSpec.getSize(heightMeasureSpec);
        mGobanWidth = min(mWidthSize!!, heightSize!!)
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
            mGobanWidth = heightSize
        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
            mGobanWidth = mWidthSize
        }
        setMeasuredDimension(mGobanWidth!!, mGobanWidth!!)
    }

    /**
     * 初始化测量数据
     */
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mPanelWidth = w;
        mLineHeight = mPanelWidth!! * 1.0f / mMaxLine!!

        mRatioHeight = (mLineHeight!! * 3.0f / 4).toInt()
        mWhiteBitmap = Bitmap.createScaledBitmap(
            mWhiteBitmap,
            mRatioHeight!!.toInt(),
            mRatioHeight!!.toInt(),
            false
        )
        mBlackBitmap = Bitmap.createScaledBitmap(
            mBlackBitmap,
            mRatioHeight!!.toInt(),
            mRatioHeight!!.toInt(),
            false
        )
    }

    /**
     * 获取自定义传递来的参数
     */
    @SuppressLint("Recycle")
    private fun initAttr(context: Context, attributeSet: AttributeSet) {
        val typearray: TypedArray =
            context.obtainStyledAttributes(attributeSet, R.styleable.GobanView)
        mGobanBgcolor = typearray.getColor(R.styleable.GobanView_gobanbgcolor, mGobanBgcolor!!)
        mGobanNumber =
            typearray.getDimension(R.styleable.GobanView_gobannubme, mGobanNumber!!.toFloat())
                .toInt()
    }

    override fun onDraw(canvas: Canvas?) {
        //绘制棋盘
        drawBoardLine(canvas)
        //绘制棋子
        drawPieces(canvas)
        checkGameOver()
    }

    private fun checkGameOver() {
        for (point in mWhitepoints) {
            //判断是否白期获胜
            mIsWhiteWin = checkisWhiteWin(point, mWhitepoints)
        }
        for (point in mBlackpoints) {
            //判断是否黑棋获胜
            mIsBlackWin = checkisBlackWin(point, mBlackpoints)
        }
        //判断是否获胜
        if (!mIsWhiteWin && !mIsBlackWin) {

        } else if (mIsWhiteWin && !mIsBlackWin) {
            isfinsh = true
            Toast.makeText(context, "白棋获胜", Toast.LENGTH_LONG).show()
            if (calledisfinish != null) {
                calledisfinish!!.isFinsh(true)
            }
            Log.e(TAG, "白棋获胜")
        } else if (mIsBlackWin && !mIsWhiteWin) {
            isfinsh = true
            Toast.makeText(context, "黑棋获胜", Toast.LENGTH_LONG).show()
            if (calledisfinish != null) {
                calledisfinish!!.isFinsh(true)
            }
            Log.e(TAG, "黑棋获胜")
        }
    }

    /**
     * 绘制棋子
     */
    private fun drawPieces(canvas: Canvas?) {
        //没结束游戏绘制
        if (!isfinsh) {
            for (i in 0 until mWhitepoints.size) {
                var whitePoint: Point = mWhitepoints[i]
                canvas!!.drawBitmap(
                    mWhiteBitmap,
                    (whitePoint.x + (1 - 3.0f / 4) / 2) * mLineHeight!!,
                    (whitePoint.y + (1 - 3.0f / 4) / 2) * mLineHeight!!,
                    null
                )
            }
            for (i in 0 until mBlackpoints.size) {
                var blackPoint: Point = mBlackpoints[i]
                canvas!!.drawBitmap(
                    mBlackBitmap,
                    (blackPoint.x + (1 - 3.0f / 4) / 2) * mLineHeight!!,
                    (blackPoint.y + (1 - 3.0f / 4) / 2) * mLineHeight!!,
                    null
                )
            }
        }


    }

    /**
     * 绘制棋盘
     */
    private fun drawBoardLine(canvas: Canvas?) {
        var w: Int? = mPanelWidth
        var lineHeight: Float? = mLineHeight

        for (i in 0..mMaxLine) {
            var startX: Int = (lineHeight!! / 2f).toInt()
            var endX: Int = (w!! - lineHeight / 2f).toInt()
            var endY: Int = ((0.5 + i) * lineHeight).toInt()
            canvas!!.drawLine(
                startX.toFloat(), endY.toFloat(), endX.toFloat(),
                endY.toFloat(), mPaint
            )
            canvas.drawLine(
                endY.toFloat(), startX.toFloat(), endY.toFloat(),
                endX.toFloat(), mPaint
            )
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (isfinsh) {
            return false
        }
        if (event!!.action == MotionEvent.ACTION_UP) {
            var eventX: Int = event.x.toInt()
            var eventY: Int = event.y.toInt()
            //将位置规整 只能下载相交线上
            var p: Point = Point((eventX / mLineHeight!!).toInt(), (eventY / mLineHeight!!).toInt())
            //判断当前位置是否有棋子
            if (mWhitepoints.contains(p) || mBlackpoints.contains(p)) {
                return false
            }
            if (!isfinsh) {
                if (mIsWhite) {
                    mWhitepoints.add(p)
                } else {
                    mBlackpoints.add(p)
                }
                invalidate()
                mIsWhite = !mIsWhite
            }
        }

        return true;
    }


    /**
     * 检测是否黑棋获胜
     */
    private fun checkisBlackWin(p: Point, mBlackpoints: MutableList<Point>): Boolean {
        //判断横排有没有构成获胜条件
        if (checkHorizontal(p, mBlackpoints)) {
            return true
        }
        //判断竖排有没有构成获胜条件
        if (checkvertical(p, mBlackpoints)) {
            return true
        }
        //判断左上右下斜有没有构成获胜条件
        if (checkleftDiagonal(p, mBlackpoints)) {
            return true
        }
        //判断右上左下斜有没有构成获胜条件
        if (checkRightDiagonal(p, mBlackpoints)) {
            return true
        }
        return false
    }

    /**
     * 检测是否白棋获胜
     */
    private fun checkisWhiteWin(p: Point, mWhitepoints: MutableList<Point>): Boolean {
        //判断横排有没有构成获胜条件
        if (checkHorizontal(p, mWhitepoints)) {
            return true
        }
        //判断竖排有没有构成获胜条件
        if (checkvertical(p, mWhitepoints)) {
            return true
        }
        //判断左上右下斜有没有构成获胜条件
        if (checkleftDiagonal(p, mWhitepoints)) {
            return true
        }
        //判断右上左下斜有没有构成获胜条件
        if (checkRightDiagonal(p, mWhitepoints)) {
            return true
        }
        return false
    }


    /**
     * 判断横排有没有构成获胜条件
     */
    private fun checkHorizontal(p: Point, mPoint: MutableList<Point>): Boolean {
        //横向左
        var count: Int = 1
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x - i, p.y))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        //横向右
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x + i, p.y))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        return false
    }

    /**
     * 判断竖排有没有构成获胜条件
     */
    private fun checkvertical(p: Point, mPoint: MutableList<Point>): Boolean {
        var count: Int = 1
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x, p.y - i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        //横向右
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x, p.y + i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        return false
    }

    /**
     * 判断左上右下斜有没有构成获胜条件
     */
    private fun checkleftDiagonal(p: Point, mPoint: MutableList<Point>): Boolean {
        var count: Int = 1
        //左上右下 上
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x - i, p.y + i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        //左上右下 下
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x + i, p.y - i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        return false
    }

    /**
     * 判断右上左下斜有没有构成获胜条件
     */
    private fun checkRightDiagonal(p: Point, mPoint: MutableList<Point>): Boolean {
        var count: Int = 1
        //右上左下 上
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x + i, p.y + i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        //右上左下 下
        for (i in 1..mMaxLine) {
            if (mPoint.contains(Point(p.x - i, p.y - i))) {
                count++
            } else {
                break
            }
        }
        if (count == 5) {
            return true
        }
        return false
    }

    /**
     * 暴露接口
     */
    private var calledisfinish: onCalledIsFinish? = null

    interface onCalledIsFinish {
        fun isFinsh(isfinish: Boolean)
    }

    fun setonCalledIsFinish(calledisfinish: onCalledIsFinish) {
        this.calledisfinish = calledisfinish
    }

    /**
     * 开始游戏
     */
    fun play() {
        if (calledisfinish != null) {
            calledisfinish!!.isFinsh(false)
        }
        isfinsh = false
        mWhitepoints.clear()
        mBlackpoints.clear()
        mIsBlackWin = false
        mIsWhiteWin = false
        invalidate()
    }

    private var INSANCE: String = "instance"
    private var INSANCE_isfinsh: String = "isfinsh"
    private var INSANCE_Whitepoints: String = "mWhitepoints"
    private var INSANCE_Blackpoints: String = "mBlackpoints"
    private var INSANCE_IsBlackWin: String = "mIsBlackWin"
    private var INSANCE_IsWhiteWin: String = " mIsWhiteWin"

    override fun onSaveInstanceState(): Parcelable? {
        var bundle: Bundle = Bundle()
        bundle.putParcelable(INSANCE, super.onSaveInstanceState())
        bundle.putBoolean(INSANCE_isfinsh, isfinsh)
        bundle.putParcelableArrayList(INSANCE_Whitepoints, mWhitepoints)
        bundle.putParcelableArrayList(INSANCE_Blackpoints, mBlackpoints)
        bundle.putBoolean(INSANCE_IsBlackWin, mIsBlackWin)
        bundle.putBoolean(INSANCE_IsWhiteWin, mIsWhiteWin)
        return bundle
    }


    override fun onRestoreInstanceState(state: Parcelable?) {
        if (state is Bundle) {
            var bundle: Bundle = Bundle(state)
            isfinsh = bundle.getBoolean(INSANCE_isfinsh)
            mWhitepoints = bundle.getParcelableArrayList(INSANCE_Whitepoints)!!
            mBlackpoints = bundle.getParcelableArrayList(INSANCE_Blackpoints)!!
            mIsBlackWin = bundle.getBoolean(INSANCE_IsBlackWin)
            mIsWhiteWin = bundle.getBoolean(INSANCE_IsWhiteWin)
            super.onRestoreInstanceState(bundle.getParcelable(INSANCE))
            return
        }
        super.onRestoreInstanceState(state)
    }

}